#!/usr/bin/env python
# coding: utf-8

# In[1]:
from mlxtend.preprocessing import TransactionEncoder
from mlxtend.frequent_patterns import apriori
from mlxtend.frequent_patterns import association_rules

# https://blog.csdn.net/qq_36523839/article/details/83960195https://blog.csdn.net/qq_36523839/article/details/83960195


import pandas as pd

# market = "hair_dryer"
# market = "microwave"
market = "pacifier"

inputexcel = pd.read_excel("../Problem_C_Data/" + market + '.xlsx', market)
# 评论的个数
num_review = len(list(inputexcel['star_rating']))
print(num_review)

xlsxxlsx = '../Problem_C_Data/good_contain.xls'
good_words = pd.read_excel(xlsxxlsx, 'Sheet1')
good_words = good_words.key.values.tolist()
xlsxxlsx = '../Problem_C_Data/bad_contain.xls'
bad_words = pd.read_excel(xlsxxlsx, 'Sheet1')
bad_words = bad_words.key.values.tolist()
# print(bad_words[1:5])
# good_words[3]


writer = pd.ExcelWriter(
    "./2e_output/apriori star rating descriptors 2e mlxtend select first contain " + market + ".xlsx", )

# In[2]:


import re


def load_selected_star(inputexcel, star_rating_12345):
    # 一行代表一个评论，一行第一个元素是star_rating
    output = []
    star_rating_list = list(inputexcel[inputexcel['star_rating'] == star_rating_12345]['star_rating'])
    review_headline_list = list(inputexcel[inputexcel['star_rating'] == star_rating_12345]['review_headline'])
    review_body_list = list(inputexcel[inputexcel['star_rating'] == star_rating_12345]['review_body'])

    for ii in range(len(star_rating_list)):
        #     用正则表达式替换掉所有不是英文字母和空格的字符变成空格
        review_headline = re.sub('[^a-zA-Z\s]', ' ', str(review_headline_list[ii]))
        review_body = re.sub('[^a-zA-Z\s]', ' ', str(review_body_list[ii]))
        #     避免review_headline最后一个单词和review_body第一个单词挨在一起，中间加个空格
        review = review_headline + ' ' + review_body
        #     小写 以空格分词
        reviews = review.lower().split(' ')
        onereview = []
        #     提取出评论文本中的每个单词
        for review_word in reviews:
            #         如果在好词列表中，那么就加进该评论对应的的词表
            if review_word in good_words:
                onereview.append(review_word)
            #         如果在坏词列表中，那么就加进该评论对应的的词表
            if review_word in bad_words:
                onereview.append(review_word)
        #     将该评论的词表添加到所有评论词表末尾
        output.append(list(str(star_rating_list[ii])) + onereview)
    return output


# In[3]:


# 选取出所有 star_rating_12345 的评论

for star_rating_12345 in range(1, 6):
    df_arr = load_selected_star(inputexcel, star_rating_12345)

    # 转换为bool值，也可以用函数转换为0、1

    te = TransactionEncoder()  # 定义模型
    df_tf = te.fit_transform(df_arr)
    # 将 True、False 转换为 0、1 # 官方给的其它方法
    # df_01 = df_tf.astype('int')

    # 将编码值再次转化为原来的商品名
    # df_name = te.inverse_transform(df_tf)

    df = pd.DataFrame(df_tf, columns=te.columns_)

    # use_colnames = True 使用元素名字
    # use_colnames = False 默认的 使用列名代表元素
    frequent_itemsets = apriori(df, min_support=0.05, use_colnames=True)

    # 频繁项集排序
    frequent_itemsets.sort_values(by='support', ascending=False, inplace=True)

    # 选择长度 >=2 的频繁项集
    # print(frequent_itemsets[frequent_itemsets.itemsets.apply(lambda x: len(x)) >= 2])

    '''
    association_rules(df, metric="confidence",
                          min_threshold=0.8,
                          support_only=False):
    
    - df：Apriori 计算后的频繁项集。
    
    - metric：
    可选值['support','confidence','lift','leverage','conviction']
    和下面的min_threshold参数配合使用
    
    - min_threshold：
    参数类型是浮点型，根据 metric 不同可选值有不同的范围，
    metric = 'support'  => 取值范围 [0,1]
    metric = 'confidence'  => 取值范围 [0,1]
    metric = 'lift'  => 取值范围 [0, inf]
    
    support_only：默认是 False。仅计算有支持度的项集，若缺失支持度则用 NaNs 填充。
    
    '''
    '''
    https://blog.csdn.net/qq_36523839/article/details/83960195
    antecedents	X	先导项	
    consequents	Y	后继项	
    antecedent support	support(X) 	先导项支持度 	
    consequent support	support(Y)	后继项支持度	
    support	support(X→Y) 	支持度	support(X∪Y) =P(X∪Y)=P(XY)
    confidence	confidence(X→Y)	置信度	support(X∪Y) /P(X)=P(Y|X)
    lift	lift(X→Y)	提升度	confidence(X→Y)/support(Y)=P(Y|X)/P(Y)
    leverage	leverage(X→Y)	杠杆率	support(X→Y)-support(X)*support(Y)
    conviction	conviction(X→Y)	确信度	(1-support(Y))/(1-confidence(X→Y))
    '''

    # metric可以有很多的度量选项，返回的表列名都可以作为参数
    association_rule = association_rules(
        frequent_itemsets, metric='confidence', min_threshold=0.3)

    # 关联规则排序 降序
    association_rule.sort_values(by='confidence', ascending=False, inplace=True)

    # print(association_rule.head())
    # print()

    association_rule = association_rule.values.tolist()

    # 查找所有 含有 star_rating_12345 的 rules_sorted
    rules_sorted_contain_star_rating_12345 = []
    for rules_sort in association_rule:
        if (str(star_rating_12345) in rules_sort[0]) or (str(star_rating_12345) in rules_sort[1]):
            rules_sorted_contain_star_rating_12345.append(rules_sort)

    column_name = ['antecedents', 'consequents', 'antecedent support',
                   'consequent support', 'support', 'confidence', 'lift', 'leverage', 'conviction']
    rules_sorted_contain_star_rating_12345 = pd.DataFrame(
        rules_sorted_contain_star_rating_12345, columns=column_name)

    print(rules_sorted_contain_star_rating_12345.head())
    print()

    rules_sorted_contain_star_rating_12345.to_excel(
        writer, sheet_name=str(star_rating_12345), index=False)

writer.save()
